home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
L' Effet Pommier 3
/
L'Effet Pommier - Volume 03.iso
/
Programmation
/
gray image 2.1
/
read_tiff.cc
< prev
next >
Wrap
Text File
|
1995-10-08
|
11KB
|
391 lines
// This may look like C code, but it is really -*- C++ -*-
/*
************************************************************************
*
* Grayscale Images
*
* Read an image from a file in the TIFF format
*
* The present TIFF reader reads a Class G TIFF file (for gray-scale
* images), See Appendix G of the TIFF specification.
*
* The program really needs the following tags
* ImageWidth
* ImageLength
* RowsPerStrip
* StripOffsets
* and can't work without them. Yet, if RowsPerStrip is left out, we
* assume there is only one strip in the image
*
* In addition, class G TIFF files are required to have the following
* tags with the following values
* SamplesPerPixel = 1
* BitsPerSample = 4 or 8
* Compression = 1 or 5(LZW)
* PhotometricInterpretation = 0 or 1
* So, if these tags are specified, the program makes sure that their values
* are those that are supposed to be for class G TIFFs.
*
* At present, no compression is supported.
*
* $Id: read_tiff.cc,v 2.0 1995/03/06 21:58:09 oleg Exp oleg $
*
************************************************************************
*/
#include "image.h"
#include "endian_io.h"
#include "tiff.h"
#include <iostream.h>
// Read a TIFF header from the file
// and check it
TIFFHeader::TIFFHeader(EndianIn& file)
{
magic = file.read_short("Reading a TIFF file magic byte");
if( magic == TIFF_BIGENDIAN )
file.set_bigendian();
else if( magic == TIFF_LITTLEENDIAN )
file.set_littlendian();
else
_error("Unknown magic word %x",magic);
version = file.read_short("Reading TIFF file version");
diroffset = file.read_long("Reading the TIFF dir offset");
}
/*
*------------------------------------------------------------------------
* TIFF Directory
*/
class TIFFDirectory;
class TIFFDirReadItem : public TIFFDirEntry
{
friend class TIFFDirectory;
// Note, this is a private constructor
// Be sure to call the load(file) function
// to finish the initialization
TIFFDirReadItem(void) { tag = 0; }
void load(EndianIn& file);
public:
void print(void) const;
};
// Load up the item from the file: finish
// the construction of the object
void TIFFDirReadItem::load(EndianIn& file)
{
tag = file.read_short("Reading dir entry");
type = file.read_short("Reading dir entry");
count = file.read_long("Reading dir entry");
val_offset = file.read_long("Reading dir entry");
}
// Print the contents of an item w/o frills
void TIFFDirReadItem::print(void) const
{
message("tag %d, %d ",tag,count);
switch(type)
{
case BYTE:
message("bytes");
break;
case ASCII:
message("characters");
break;
case SHORT:
message("short ints");
break;
case LONG:
message("long ints");
break;
case RATIONAL:
message("rational numbers");
break;
default:
_error("Invalid type %d",type);
}
message(" value %d (0x%x)\n",val_offset,val_offset);
}
class TIFFDirectory
{
int no_entries;
TIFFDirReadItem * entries;
public:
TIFFDirectory(EndianIn& file);
~TIFFDirectory(void);
void print(void) const;
// Look up a scalar value in the directory
unsigned long int look_up(const unsigned short tag,
const unsigned long default_value) const;
// Look up a string info and read the string
char * read_str(const unsigned short tag, EndianIn& file) const;
// Look up an item in the directory by its
// tag. Return 0 if not found
TIFFDirReadItem * look_up(const unsigned short tag) const;
};
// Load up the directory from the file
TIFFDirectory::TIFFDirectory(EndianIn& file)
{
TIFFHeader header(file);
assert( file.seekg(header.directory_offset()).good() );
no_entries = file.read_short("no of entries");
entries = new TIFFDirReadItem[no_entries];
register int i;
for(i=0; i<no_entries; i++)
entries[i].load(file);
const int offset_to_next_dir = file.read_long("reading dir");
if( offset_to_next_dir != 0 )
message("The TIFF file contains several images, only the first one "
"is going to be considered");
}
// Destroy all entries in the directory
TIFFDirectory::~TIFFDirectory(void)
{
assert( entries != 0 );
delete [] entries;
}
// Print the contents of the directory
void TIFFDirectory::print(void) const
{
register int i;
message("\nThere are %d entries in the TIFF file directory\nThey are\n",
no_entries);
for(i=0;i<no_entries; i++)
entries[i].print();
}
// Look up an item in the directory by its
// tag. Return 0 if not found
// Note, we take advantage of the fact
// that all items in the directory are
// in the ascending order of their tags
TIFFDirReadItem * TIFFDirectory::look_up(const unsigned short tag) const
{
int lo = 0; // Using a binary search
int hi = no_entries;
while( hi > lo )
{
int middle = (hi+lo)/2;
if( entries[middle].tag == tag )
return &entries[middle];
else if( entries[middle].tag > tag )
hi = middle;
else
lo = middle+1;
}
return 0; // Means not found
}
// Look up a scalar value in the directory
unsigned long int TIFFDirectory::look_up(const unsigned short tag,
const unsigned long default_value) const
{
TIFFDirEntry * entryp = look_up(tag);
if( entryp == 0 )
return default_value;
assert( entryp->tag == tag);
assert( entryp->count == 1 ); // Check that the value is scalar
// Note, if the value is shorter
// than long, it's LEFT justified
switch( entryp->type )
{
case TIFFDirEntry::BYTE:
case TIFFDirEntry::ASCII:
return (entryp->val_offset) >> 24;
case TIFFDirEntry::SHORT:
return (entryp->val_offset) >> 16;
case TIFFDirEntry::LONG:
case TIFFDirEntry::RATIONAL:
return (entryp->val_offset);
default:
_error("Invalid type %d",entryp->type);
}
}
// Look up a string value in the directory
// and return a dynamically allocated str
// Return 0 if not found
char * TIFFDirectory::read_str(const unsigned short tag, EndianIn& file) const
{
TIFFDirEntry * entryp = look_up(tag);
if( entryp == 0 )
return 0;
assert( entryp->tag == tag);
assert( entryp->type == TIFFDirEntry::ASCII );
int size = entryp->count;
if( size <= 0 )
return 0;
char * str = new char[size];;
assert( file.seekg(entryp->val_offset).good() );
file.read(str,size);
if( str[size-1] != '\0' ) // Make sure the str is terminated
str[size-1] = '\0'; // properly
return str;
}
class TIFFReadStrips
{
int no_strips;
int rows_per_strip;
unsigned long int * strip_offsets;
public:
TIFFReadStrips(const TIFFDirectory& directory,const int _rows_per_strip,
EndianIn& file);
TIFFReadStrips(void);
~TIFFReadStrips(void);
void read(IMAGE& image, EndianIn& file);
};
TIFFReadStrips::TIFFReadStrips(const TIFFDirectory& directory,
const int _rows_per_strip,
EndianIn& file)
: rows_per_strip(_rows_per_strip)
{
TIFFDirEntry * entryp = directory.look_up(TIFFTAG_STRIPOFFSETS);
assure( entryp != 0, "STRIPOFFSETS tag must be present in the TIFF file");
no_strips = entryp->count;
assert( no_strips > 0 );
strip_offsets = new unsigned long[no_strips];
if( no_strips == 1 ) // The value is coded within the
{ // dir entry itself
if( entryp->type == TIFFDirEntry::SHORT )
strip_offsets[0] = (entryp->val_offset) >> 16;
else if( entryp->type == TIFFDirEntry::LONG )
strip_offsets[0] = entryp->val_offset;
else
_error("StripOffsets must contain either LONG or SHORT values");
return;
}
// Otherwise we got to read them,
// I mean, the strip offsets
assert( file.seekg(entryp->val_offset).good() );
register int i;
for(i=0; i<no_strips; i++)
if( entryp->type == TIFFDirEntry::SHORT )
strip_offsets[i] = file.read_short("Reading StripOffsets");
else if( entryp->type == TIFFDirEntry::LONG )
strip_offsets[i] = file.read_long("Reading StripOffsets");
else
_error("StripOffsets must contain either LONG or SHORT values");
}
TIFFReadStrips::~TIFFReadStrips(void)
{
assert( strip_offsets != 0 );
delete [] strip_offsets;
}
// Read in the strips into the image
void TIFFReadStrips::read(IMAGE& image, EndianIn& file)
{
register int strip;
for(strip=0; strip<no_strips; strip++)
{
assert( file.seekg(strip_offsets[strip]).good() );
register int i,j; // Reading a strip
for(i=strip*rows_per_strip;
i<(strip+1)*rows_per_strip && i < image.q_nrows(); i++)
for(j=0; j<image.q_ncols(); j++)
image(i,j) = file.read_byte("reading a strip");
}
}
/*
*========================================================================
* Root module - actual IMAGE constructor
*/
void IMAGE::read_tiff(EndianIn& file, const bool verbose)
{
message("Reading the TIFF file\n");
TIFFDirectory directory(file);
if( verbose )
directory.print();
int no_cols = directory.look_up(TIFFTAG_IMAGEWIDTH,0);
if( no_cols == 0 )
_error("ImageWidth tag missing or improperly specified as 0");
int no_rows = directory.look_up(TIFFTAG_IMAGELENGTH,0);
if( no_rows == 0 )
_error("ImageLength tag missing or improperly specified as 0");
// Checking if we can handle this
assert( directory.look_up(TIFFTAG_SAMPLESPERPIXEL,1) == 1 );
assert( directory.look_up(TIFFTAG_BITSPERSAMPLE,1) == 8 );
assert( directory.look_up(TIFFTAG_COMPRESSION,COMPRESSION_NONE) ==
COMPRESSION_NONE );
int photometry = directory.look_up(TIFFTAG_PHOTOMETRIC,
PHOTOMETRIC_MINISBLACK);
assert( photometry == PHOTOMETRIC_MINISBLACK ||
photometry == PHOTOMETRIC_MINISWHITE );
int rows_per_strip = directory.look_up(TIFFTAG_ROWSPERSTRIP,no_rows);
TIFFReadStrips strips(directory,rows_per_strip,file);
allocate(no_rows,no_cols,8);
{
char * descr = directory.read_str(TIFFTAG_IMAGEDESCRIPTION,file);
char * doc_name = directory.read_str(TIFFTAG_DOCUMENTNAME,file);
if( descr != 0 || doc_name != 0 )
if( doc_name == 0 )
name = descr;
else if( descr == 0 )
name = doc_name;
else
name = strcat(
strcat(
strcpy(new char[strlen(descr)+strlen(doc_name)+2],
descr),"/"),doc_name),
delete descr, delete doc_name;
}
strips.read(*this,file);
if( photometry == PHOTOMETRIC_MINISWHITE )
invert();
cout << "\n" << no_cols << "x" << no_rows << "x" << q_depth() << " image '"
<< name << "' has been read" << endl;
}